package com.nan.gbd.library.extractor;

import android.media.MediaCodec;
import android.media.MediaExtractor;
import android.media.MediaFormat;

import com.nan.gbd.library.codec.MediaCodecConstant;
import com.nan.gbd.library.utils.Logger;

import java.io.IOException;
import java.nio.ByteBuffer;

/**
 * 音频解码线程
 */
public class AudioExtractorThread extends Extractor {
    private MediaCodec mediaCodec;
    private ByteBuffer[] inputBuffers;
    private ByteBuffer[] outputBuffers;
    private MediaCodec.BufferInfo audioBufferInfo;
    private static final long TIMEOUT_US = 1000;

    public AudioExtractorThread(String filePath) {
        super(filePath);
    }


    @Override
    public void run() {
        int audioTrackIndex = getTrackIndex(mediaExtractor, "audio/");
        if (audioTrackIndex < 0) return;
        MediaFormat mediaFormat = mediaExtractor.getTrackFormat(audioTrackIndex);

        if (extractorListener != null) {
            extractorListener.audioAspect(mediaFormat);
        }
        mediaExtractor.selectTrack(audioTrackIndex);

        initMediaCodec(mediaFormat);
        startMs = System.currentTimeMillis();
        while (!Thread.interrupted()) {
            if (!isPlaying) {
                try {
                    sleep(50);
                    continue;
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            if (isPlaying) {
                // 暂停
                if (isPause) {
                    continue;
                }
                // 解码
                extractorMediaData();
                seekToUs = -1;
            }
        }
        // 释放MediaCode 和AudioTrack
        if (mediaExtractor != null) {
            mediaExtractor.release();
            mediaExtractor = null;
        }
        if (mediaCodec != null) {
            mediaCodec.stop();
            mediaCodec.release();
            mediaCodec = null;
        }
    }


    /**
     * 解复用，得到需要解码的数据
     *
     * @return
     */
    @Override
    protected void extractorMediaData() {
        if (MediaCodecConstant.audioStop) return;

        decodeMediaData(mediaExtractor, mediaCodec, inputBuffers);

        // 获取解码后的数据
        int outputBufferIndex = mediaCodec.dequeueOutputBuffer(audioBufferInfo, TIMEOUT_US);

        if (outputBufferIndex == MediaCodec.INFO_TRY_AGAIN_LATER) {
            Logger.e("dequeueOutputIndex==MediaCodec.INFO_TRY_AGAIN_LATER");
        } else if (outputBufferIndex == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
            Logger.e("dequeueOutputIndex==MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED");
            outputBuffers = mediaCodec.getOutputBuffers();
        } else if (outputBufferIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
            Logger.e("dequeueOutputIndex==MediaCodec.INFO_OUTPUT_FORMAT_CHANGED");
            MediaFormat outputFormat = mediaCodec.getOutputFormat();
        } else {
            while (outputBufferIndex >= 0) {
                ByteBuffer outputBuffer = outputBuffers[outputBufferIndex];

                // 延时解码，跟视频时间同步
                decodeDelay(audioBufferInfo);

                Logger.e("音频解码数据：" + audioBufferInfo.size);
                if (audioBufferInfo.size > 0) {
                    byte[] mAudioOutTempBuf = new byte[audioBufferInfo.size];
                    outputBuffer.get(mAudioOutTempBuf);
                    outputBuffer.clear();
                    if (extractorListener != null) {
                        extractorListener.audioDatas(mAudioOutTempBuf);
                    }
                }
                // 释放资源
                mediaCodec.releaseOutputBuffer(outputBufferIndex, false);
                outputBufferIndex = mediaCodec.dequeueOutputBuffer(audioBufferInfo, TIMEOUT_US);

            }
        }
        if ((audioBufferInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {// 编解码结束
            Logger.e("语音 数据播放完了 end of stream");
            MediaCodecConstant.audioStop = true;
            if (extractorListener != null && MediaCodecConstant.videoStop) {
                extractorListener.endStream();
            }
            Logger.e("语音 数据播放完了 end of stream");
            return;
        }
    }


    private void initMediaCodec(MediaFormat mediaFormat) {
        String mime = mediaFormat.getString(MediaFormat.KEY_MIME);
        try {
            mediaCodec = MediaCodec.createDecoderByType(mime);
            mediaCodec.configure(mediaFormat, null, null, 0);
        } catch (IOException e) {
            e.printStackTrace();
        }
        if (mediaCodec == null) {
            Logger.e("audio decoder is unexpectedly null");
            return;
        }
        audioBufferInfo = new MediaCodec.BufferInfo();
        mediaCodec.start();
        inputBuffers = mediaCodec.getInputBuffers();
        outputBuffers = mediaCodec.getOutputBuffers();
    }


    /**
     * 解复用，得到需要解码的数据
     *
     * @param extractor
     * @param decoder
     * @param inputBuffers
     * @return
     */
    private void decodeMediaData(MediaExtractor extractor, MediaCodec decoder, ByteBuffer[] inputBuffers) {
        int inputBufferIndex = decoder.dequeueInputBuffer(TIMEOUT_US);
        if (inputBufferIndex >= 0) {
            ByteBuffer inputBuffer = inputBuffers[inputBufferIndex];
            inputBuffer.clear();
            if (seekToUs != -1) {
                extractor.seekTo(seekToUs, MediaExtractor.SEEK_TO_NEXT_SYNC);
            }
            int sampleSize = extractor.readSampleData(inputBuffer, 0);
            if (sampleSize < 0) {
                decoder.queueInputBuffer(inputBufferIndex, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM);
            } else {
                decoder.queueInputBuffer(inputBufferIndex, 0, sampleSize, extractor.getSampleTime(), 0);
                extractor.advance();
            }
        }
    }


    /**
     * 解码延时
     *
     * @param bufferInfo
     */
    private void decodeDelay(MediaCodec.BufferInfo bufferInfo) {
        long systemTimes = System.currentTimeMillis() - startMs;
        long ptsTimes = bufferInfo.presentationTimeUs / 1000;
        long timeDifference = ptsTimes - systemTimes;
        if (timeDifference > 0) {
            try {
                Logger.e("===audio=====decodeDelay===" + timeDifference);
                sleep(timeDifference);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    public void release() {
        super.release();
        if (mediaCodec != null) {
            mediaCodec.release();
            mediaCodec = null;
        }
        inputBuffers = null;
        outputBuffers = null;
        audioBufferInfo = null;
    }
}
